package com.tsingtao.arch.rule;

import static com.societegenerale.commons.plugin.utils.ArchUtils.importAllClassesInPackage;
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
import static com.tsingtao.arch.rule.ApiRulesTest.API;
import static com.tsingtao.arch.rule.ControllerRulesTest.CONTROLLER;
import static com.tsingtao.arch.rule.MybatisMapperRulesTest.MYBATIS_MAPPER;

import com.societegenerale.commons.plugin.rules.ArchRuleTest;
import com.societegenerale.commons.plugin.service.ScopePathProvider;
import com.tngtech.archunit.library.Architectures.LayeredArchitecture;
import java.util.Collection;

/**
 * 架构分层规则
 */
public class LayeredArchitectureTest implements ArchRuleTest {

  private static final String LAYER_CONTROLLER = "Controller";
  public static final String LAYER_PERSISTENT = "Persistent";
  public static final String LAYER_API = "API";
  public static final String LAYER_SERVICE = "Service";
  public static final String LAYER_CONSUMER = "Consumer";
  public static final String LAYER_PRODUCER = "Producer";

  public static final String LAYER_JOB = "Job";

  private final LayeredArchitecture LAYERS = layeredArchitecture()
      .layer(LAYER_CONTROLLER).definedBy(CONTROLLER)
      .layer(LAYER_SERVICE).definedBy(ServiceRulesTest.SERVICE)
      .layer(LAYER_API).definedBy(API)
      .layer(LAYER_PERSISTENT).definedBy(MYBATIS_MAPPER)
      .layer(LAYER_CONSUMER).definedBy(MqRulesTest.CONSUMER)
      .layer(LAYER_PRODUCER).definedBy(MqRulesTest.PRODUCER)
      .layer(LAYER_JOB).definedBy("..job..");

  @Override
  public void execute(String packagePath, ScopePathProvider scopePathProvider, Collection<String> excludedPaths) {
    LAYERS.whereLayer(LAYER_CONTROLLER).mayNotBeAccessedByAnyLayer()
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

    LAYERS.whereLayer(LAYER_API).mayOnlyBeAccessedByLayers(LAYER_SERVICE)
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

    LAYERS.whereLayer(LAYER_SERVICE).mayOnlyBeAccessedByLayers(LAYER_CONTROLLER, LAYER_CONSUMER, LAYER_JOB)
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

    LAYERS.whereLayer(LAYER_PERSISTENT).mayOnlyBeAccessedByLayers(LAYER_SERVICE, LAYER_JOB)
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

    LAYERS.whereLayer(LAYER_CONSUMER).mayNotBeAccessedByAnyLayer()
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

    LAYERS.whereLayer(LAYER_PRODUCER).mayOnlyBeAccessedByLayers(LAYER_SERVICE)
        .allowEmptyShould(true)
        .check(importAllClassesInPackage(scopePathProvider.getMainClassesPath(), packagePath, excludedPaths));

  }
}